//
//  State.cpp
//  derleyici
//
//  Created by Avea on 12/17/11.
//  Copyright (c) 2011 __MyCompanyName__. All rights reserved.
//

#include "State.h"

State::State(int id){
    identifier = id;
}

int State::getIdentifier(){
    return identifier;
}
void State::addItemToItems(Item *aItem){
    if(!isItemOnTheList(aItem))
        items.push_back(aItem);
}


void State::addGoTo(Symbol *aSymbol,State *aState){
    bool alreadyInList = false;
    multimap<Symbol *, State *>::iterator it;
    for (it = goToMap.begin(); it != goToMap.end(); it++) {
        if(((*it).first->getIdentifier()==aSymbol->getIdentifier()) && ((*it).second->getIdentifier()==aState->getIdentifier())){
            alreadyInList = true;
            break;
        }
    }
    if(!alreadyInList)
        goToMap.insert(pair<Symbol *,State *>(aSymbol,aState));
}

bool State::isItemOnTheList(Item *aItem){
    bool result = false;
    for(int i=0; i<items.size(); i++){
        //cout<<"Karsilastirma ";
        //aItem->printSymbols();
        //cout<<" ile ";
        //items[i]->printSymbols();
        //cout<<" arasinda"<<endl;
        if(aItem->operator==(items[i])){
            result = true;
            break;
        }
    }
    return result;
}


void State::printItems(){
    cout<<identifier<<" items"<<endl;
    for(int i=0; i<items.size(); i++){
        items[i]->printSymbols();
        cout<<endl;
    }
}

void State::printGoToMap(){
    cout<<identifier<<" goto's"<<endl;
    multimap<Symbol *, State *>::iterator it;
    for (it = goToMap.begin(); it != goToMap.end(); it++) {
        cout<<(*it).first->getIdentifier() <<" -> "<< (*it).second->getIdentifier() <<endl;
    }
    cout<<endl;
}

bool State::findItemsForGivenItem(Item *aItem){
    bool founded = false;
    //aItem->printSymbols();
    if((aItem->getDotLocation()<aItem->getSymbols().size())){
        //cout<<"geldim"<<endl;
        /** Parçanın noktadan sonra gelen elemanı nonterminal mi **/
        if(isupper(aItem->getNextSymbolFromDot()->getIdentifier().c_str()[0])>0){
            //cout<<"geldim"<<endl;
            /** nonterminalin referansını getir **/
            Nonterminal *nonterm = (Nonterminal *)aItem->getNextSymbolFromDot();
            vector<Rule> rules;
            Item *newItem;
            
            /** nonterminalin kurallarını getir **/
            rules = nonterm->getRules();
            for(int i=0; i<rules.size(); i++){
                
                /** her kural için yeni bir parça yaratıp state'e ekle **/
                newItem = new Item(&rules[i],0);
                //cout<<"yeni yaratilan item:";
                //newItem->printSymbols();
                
                /** TO-DO: Parçaların sonraki sözcük kümeleri belirlenecek **/
                /** nokta sonda ise sonraki sözcüğün ilk elemanının firstünü ekle **/
                if(aItem->isDotAtEnd() || (aItem->getDotLocation()+1==aItem->getSymbols().size())){
                    //aItem->printSymbols();
                    //newItem->addSymbolToNextSymbols(aItem->getNextSymbols()[0]->getFirstSet()[0]);
                    for(int x=0; x<aItem->getNextSymbols().size(); x++){
                        newItem->addSymbolToNextSymbols(aItem->getNextSymbols()[x]->getFirstSet()[0]);
                    }
                
                /** nokta sonda değilse noktadan sonra gelen nonterminalden sonraya bak **/
                }else{
                    //cout<<"Giren:";
                    //aItem->printSymbols();
                    //cout<<"karakter:"<<aItem->getSymbols()[aItem->getDotLocation()+1]->getIdentifier()<<endl;
                    newItem->addSymbolToNextSymbols(aItem->getSymbols()[aItem->getDotLocation()+1]->getFirstSet()[0]);
                    //newItem->printSymbols();
                }
                
                addItemToItems(newItem);
                founded = true;
            }
        }
    }
    
    return founded;
}
//Sorun findItemsForGiven false dönüyor ama listede halen taranmamış item var..
void State::findAllItems(){
    for(int i=0; i<items.size(); i++){
        findItemsForGivenItem(items[i]);
    }
    allItemFounded = true;
}

bool State::isAllItemFounded(){
    return allItemFounded;
}

vector<Item *> State::getItems(){
    return items;
}


bool State::isSymbolOnTheMapThenAddItemToState(Symbol *aSymbol, Item *aItem){
    bool result = false;
    multimap<Symbol *, State *>::iterator it;
    for (it = goToMap.begin(); it != goToMap.end(); it++) {
        if((*it).first->getIdentifier().compare(aSymbol->getIdentifier())==0){
            result = true;
            (*it).second->addItemToItems(aItem);
            //cout<<"Eklendi: "<<(*it).first->getIdentifier() <<" -> "<< (*it).second->getIdentifier() <<endl;
            break;
        }
    }
    return result;
}

void State::findPossibleGoTos(){
    
}

State* State::getMapStateBySymbol(Symbol *aSymbol){
    State *state;
    multimap<Symbol *, State *>::iterator it;
    for (it = goToMap.begin(); it != goToMap.end(); it++) {
        if((*it).first->getIdentifier().compare(aSymbol->getIdentifier())==0){
            state = (*it).second;
            break;
        }
    }
    return state;
}

bool State::isSymbolOnTheMap(Symbol *aSymbol){
    bool result = false;
    multimap<Symbol *, State *>::iterator it;
    for (it = goToMap.begin(); it != goToMap.end(); it++) {
        if((*it).first->getIdentifier().compare(aSymbol->getIdentifier())==0){
            result = true;
            break;
        }
    }
    return result;
}

bool State::isSymbolReducible(Symbol *aSymbol){
    bool reducible = false;
    for(int i=0; i<items.size(); i++){ //Tüm parçaları iterate et
        if(items[i]->isDotAtEnd() && items[i]->hasNextSymbol(aSymbol)){ // İndirgenebilir durumda olan parçalarda nokta sondadır, sonraki sözcüklerde sembol aranır
            reducible = true;
            break;
        }
    }
    return reducible;
}
Rule* State::getReductionBySymbol(Symbol *aSymbol){
    Rule *rule;
    for(int i=0; i<items.size(); i++){ //Tüm parçaları iterate et
        if(items[i]->isDotAtEnd() && items[i]->hasNextSymbol(aSymbol)){ // İndirgenebilir durumda olan parçalarda nokta sondadır, sonraki sözcüklerde sembol aranır
            //cout<<items[i]->getNumber()<<endl;
            rule=items[i];
            break;
        }
    }
    return rule;
}




